// Copyright 2022 jeff.li. and/or its affiliates.

#include <tbir/pipeline/symbolic_executor.h>

#include <tbir/pipeline/global_unique_index.h>

namespace tbir::runtime {

    std::vector<std::unique_ptr<Symbol>> SymbolicExecutor::Compose(
            OpKernelPtr op,
            const std::vector<const Symbol *> &args,
            const ska::flat_hash_map<String, const Symbol *> &kwargs,
            int num_output) {
        MXCHECK(kwargs.empty()) << "named args is not unsupported";
        // dynamic graphs generate symbols on demand,
        // so there is no need to repeat checks in the symbol executor

        // make a new node
        NodePtr node = Node::Create();
        node->op = op;
        node->name.append(op->name_).append("_node_");
        String input_node_names;
        for (size_t i = 0; i < args.size(); ++i) {
            auto &sym = args[i];
            node->inputs.push_back(sym->GetEntry());
            for (auto &o : sym->GetAllEntries()) {
                if (sym->GetEntry() != o) {
                    node->holder.push_back(o);
                }
            }
            if (i + 1 == args.size()) {
                input_node_names.append(sym->GetEntry()->Name());
            } else {
                input_node_names.append(sym->GetEntry()->Name()).push_back('+');
            }
        }
        auto input_node_hash =
                std::to_string(BytesHash(input_node_names.data(), input_node_names.size()));
        node->name.append(input_node_hash.data(), input_node_hash.size());
        uint64_t node_key = GlobalUniqueIndex::instance()->gen_uniq_signature(node->name);

        std::vector<NodeEntryPtr> outputs;
        for (size_t i = 0; i < num_output; ++i) {
            auto entry_o_i = std::make_shared<NodeEntry>();
            entry_o_i->init(node, i, node_key);
            outputs.push_back(std::move(entry_o_i));
        }
        node->outputs = MakeNodeOutputs(outputs);
        std::vector<std::unique_ptr<Symbol>> symbolic_outputs;
        for (size_t i = 0; i < num_output; ++i) {
            symbolic_outputs.push_back(std::make_unique<Symbol>(outputs, i));
        }
        return symbolic_outputs;
    }

}  // namespace tbir::runtime
